package com.ruoyi.SSL.task;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.Method;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ruoyi.SSL.domain.SslApply;
import com.ruoyi.SSL.domain.SslCloudProductDeploy;
import com.ruoyi.SSL.domain.SslDomain;
import com.ruoyi.SSL.domain.SslDomainRrVal;
import com.ruoyi.SSL.service.*;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.CommUtils;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.SignUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.utils.aly.AlyDomainApiUtils;
import org.springframework.boot.web.server.Ssl;
import org.springframework.stereotype.Component;

import java.io.FileInputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 定时任务调度测试
 *
 * @author ruoyi
 */
@Component("SSLTask")
public class SSLTask
{
    private final ISslApplyService applyService = SpringUtils.getBean(ISslApplyService.class);
    private final ISslDomainService domainService = SpringUtils.getBean(ISslDomainService.class);
    private final ISysConfigService configService = SpringUtils.getBean(ISysConfigService.class);
    private final ISslNotificationLogService warmLogService = SpringUtils.getBean(ISslNotificationLogService.class);
    private final IAutoDeployService autoDeployService = SpringUtils.getBean(IAutoDeployService.class);
    private final ISslCloudProductDeployService cloudProductDeployService = SpringUtils.getBean(ISslCloudProductDeployService.class);

    /**
     * 定时检查待签发的证书进行签发操作
     */
    public void run(){
        SslApply apply1 = null;
        try {
            //查询是否存在签发中的订单
            SslDomain domainQuery = new SslDomain();
            domainQuery.setWhereSql(" AND a.status != '-1' AND a.status != 3 AND a.status != 4 AND a.status != 5");
            //查询数据
            List<SslDomain> domainList = domainService.selectSslDomainList(domainQuery);
            //循环查询证书是否已经签发完成
            for (SslDomain domain : domainList) {
                if(StrUtil.isBlankIfStr(domain.getSslApplyId())){
                    domain.setStatus("5");
                    //修改数据
                    domainService.updateSslDomain(domain);
                    continue;
                }
                //查询申请记录
                apply1 = applyService.selectSslApplyById(domain.getSslApplyId());
                //如果申请记录为空 啧直接失败
                if(apply1 == null){
                    domain.setStatus("5");
                    //修改数据
                    domainService.updateSslDomain(domain);
                    continue;
                }
                try {
                    HttpRequest request = HttpRequest.get(CommUtils.REQ_API_URI+"/SSL/api/v1/getSslInfoStatus");
                    //先封装参数得到签名值
                    JSONObject paramObj = new JSONObject();
                    paramObj.set("serRecordCode", apply1.getSerRecordCode());
                    //得到签名
                    String sign = SignUtils.createSign(paramObj, configService.selectConfigByKey("api.appSecret"));
                    //赋值必要请求头的值
                    request.header("Referer", configService.selectConfigByKey("self.domain"));
                    request.header("ssl-sign", sign);   //签名字符串
                    request.header("ssl-appid", configService.selectConfigByKey("api.appId"));  //appid
                    request.header("ssl-timestamp", String.valueOf(DateUtil.current()));    // 当前时间戳
                    //把请求参数赋值到请求中
                    request.body(JSONUtil.toJsonStr(paramObj));
                    //发起请求
                    HttpResponse response = request.execute();
                    if(response.getStatus() == 200){
                        JSONObject resObj = JSONUtil.parseObj(response.body());
                        if(resObj.getInt("code") == 0){
                            SslApply  applyTmp = JSONUtil.toBean(resObj.getStr("data"), SslApply.class);
                            apply1.setStatus(applyTmp.getStatus());
                            //保存数据
                            applyService.updateSslApply(apply1);
                            //更改域名记录的状态
                            domain.setStatus(applyTmp.getStatus());//更改状态
                            domainService.updateSslDomain(domain);
                            //判断状态
                            if(StrUtil.equals(applyTmp.getStatus(), "3")){
                                String filePath1 = FileUtils.writeTxtInFile(applyTmp.getSslKeyContent(), IdUtils.fastSimpleUUID() +".key");
                                String filePaht2 = FileUtils.writeTxtInFile(applyTmp.getSslPemContent(), IdUtils.fastSimpleUUID()+".pem");
                                try {
                                    //保存证书过期时间
                                    apply1.setSslCreateTime(applyTmp.getSslCreateTime());
                                    apply1.setExpiredTime(applyTmp.getExpiredTime());
                                    apply1.setSslFilePath(filePath1+","+filePaht2);
                                    //保存数据
                                    applyService.updateSslApply(apply1);
                                    //更改域名记录的状态
                                    domain.setDeployStatus("N");
                                    domainService.updateSslDomain(domain);
                                    String content ="域名#info#"+apply1.getCertificateDomain()+","
                                            +"生效时间#info#"+DateUtil.format(apply1.getSslCreateTime(), "yyyy-MM-dd HH:mm")+","
                                            +"到期时间#info#"+DateUtil.format(apply1.getExpiredTime(), "yyyy-MM-dd HH:mm")+",";
                                    //发送通知
                                    warmLogService.insertLog("1", apply1.getCertificateDomain(), "["+apply1.getCertificateDomain()+"]证书签发成功！",content);
                                    //判断是否存在云产品
                                    AjaxResult aj = configService.getPlatformInfoByAppId(CommUtils.REQ_API_URI, configService.selectConfigByKey("api.appId"), configService.selectConfigByKey("api.appSecret"));
                                    int dayNum = 0;
                                    if(aj.isSuccess()){
                                        JSONObject platformInfoJson = JSONUtil.parseObj(aj.get("data"));
                                        dayNum = platformInfoJson.getInt("renewBeforeDays");
                                    }else{
                                        dayNum = 5;
                                    }
                                    SslCloudProductDeploy cloudProductDeploy = new SslCloudProductDeploy();
                                    cloudProductDeploy.setDomainTxt(apply1.getCertificateDomain());
                                    cloudProductDeploy.setIsAutoSsl("Y");
                                    cloudProductDeploy.setWhereSql("AND auto_expired_time > '"+DateUtil.format(new Date(),  DatePattern.NORM_DATETIME_PATTERN)+"' and DATEDIFF(expired_time, CURDATE()) <=" +dayNum);
                                    List<SslCloudProductDeploy> cloudProductDeployList = cloudProductDeployService.selectSslCloudProductDeployList(cloudProductDeploy);
                                    for (SslCloudProductDeploy sslCloudProductDeploy : cloudProductDeployList) {
                                        sslCloudProductDeploy.setExpiredTime(applyTmp.getExpiredTime());
                                        sslCloudProductDeploy.setDeployStatus("N");
                                        //保存数据
                                        cloudProductDeployService.updateSslCloudProductDeploy(sslCloudProductDeploy);
                                        aj = autoDeployService.deploySsl(sslCloudProductDeploy.getId());
                                        String cloudContent ="云厂商#info#"+DictUtils.getDictLabel("cloud_vendor", sslCloudProductDeploy.getCloudVendor())+","
                                                +"云产品#info#"+(StrUtil.isBlank(DictUtils.getDictLabel("cloud_product", sslCloudProductDeploy.getCloudProduct()))?"未获取到信息":DictUtils.getDictLabel("cloud_product", sslCloudProductDeploy.getCloudProduct()))+","
                                                +"域名#info#"+sslCloudProductDeploy.getCertificateDomain()+",";
                                        if(aj.isSuccess()){
                                            warmLogService.insertLog("1", sslCloudProductDeploy.getCertificateDomain(), "云产品自动续签部署成功！", cloudContent);
                                            Console.log("自动部署云产品，云厂商：{}，云产品：{}，域名：{}，状态：{}", sslCloudProductDeploy.getCloudVendor(), sslCloudProductDeploy.getCloudProduct(), sslCloudProductDeploy.getCertificateDomain(), "自动部署成功！");
                                        }else{
                                            warmLogService.insertLog("1", sslCloudProductDeploy.getCertificateDomain(), "云产品自动续签部署失败！", cloudContent);
                                            Console.log("自动部署云产品，云厂商：{}，云产品：{}，域名：{}，状态：{}", sslCloudProductDeploy.getCloudVendor(), sslCloudProductDeploy.getCloudProduct(), sslCloudProductDeploy.getCertificateDomain(), "自动部署失败！");
                                        }
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    String content ="错误描述#info#证书过期时间获取失败";
                                    warmLogService.insertLog("1", apply1.getCertificateDomain(), "["+apply1.getCertificateDomain()+"]证书签发失败！",content);
                                    Console.error("发生错误证书：{}，错误问题：证书过期时间获取失败！", apply1.getCertificateDomain());
                                }
                            }else{
                                //判断是否存在云产品
                                SslCloudProductDeploy cloudProductDeploy = new SslCloudProductDeploy();
                                cloudProductDeploy.setDomainTxt(apply1.getCertificateDomain());
                                List<SslCloudProductDeploy> cloudProductDeployList = cloudProductDeployService.selectSslCloudProductDeployList(cloudProductDeploy);
                                for (SslCloudProductDeploy sslCloudProductDeploy : cloudProductDeployList) {
                                    sslCloudProductDeploy.setStatus(applyTmp.getStatus());
                                    //保存数据
                                    cloudProductDeployService.updateSslCloudProductDeploy(sslCloudProductDeploy);
                                }
                            }
                        }else{
                            String content ="错误描述#info#获取证书失败！";
                            warmLogService.insertLog("1", apply1.getCertificateDomain(), "["+apply1.getCertificateDomain()+"]获取证书失败！",content);
                            Console.error("发生错误证书：{}，错误问题：获取证书失败！", apply1.getCertificateDomain());
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
                //打印信息
                Console.error("域名：{}，签发状态：{}", apply1.getCertificateDomain(), DictUtils.getDictLabel("ssl_status", apply1.getStatus()));
            }
        } catch (NumberFormatException e) {
            String content ="错误描述#info#异常错误，请联系负责人";
            warmLogService.insertLog("1", apply1.getCertificateDomain(), "["+apply1.getCertificateDomain()+"]证书签发失败！",content);
            Console.error("执行异常：{}", e.getMessage());
        }
    }

    /**
     * 定时检查快要到期的证书，进行重新续签和部署
     * @throws InterruptedException
     */
    public void runCheckExpiredTime() throws InterruptedException {
        //查询开启自动续签且达到续签标准的记录
        SslDomain sslDomain = new SslDomain();
        sslDomain.setIsAutoSsl("Y");
        AjaxResult aj = configService.getPlatformInfoByAppId(CommUtils.REQ_API_URI, configService.selectConfigByKey("api.appId"), configService.selectConfigByKey("api.appSecret"));
        if(aj.isSuccess()){
            JSONObject platformInfoJson = JSONUtil.parseObj(aj.get("data"));
            sslDomain.setDaysDifference(platformInfoJson.getInt("renewBeforeDays"));
        }else{
            sslDomain.setDaysDifference(5);
        }
        sslDomain.setAutoDaysDifference(0);
        List<SslDomain> domainList = domainService.selectSslDomainList(sslDomain);
        //循环续签每一个域名证书
        for (SslDomain domain : domainList) {
            aj = domainService.applySSL(domain);
            Console.error("检测自动续签域名：{}，结果：{}，描述信息：{}", domain.getCertificateDomain(), aj.isSuccess()?"发起成功！":"发起失败！",aj.get("msg"));
        }
        Console.log("===========检查续费期限到期域名============");
        sslDomain = new SslDomain();
        sslDomain.setIsYzOver("Y");
        sslDomain.setWhereSql(" HAVING (auto_days_difference < 1 and days_difference is not null)");
        domainList = domainService.selectSslDomainList(sslDomain);
        for (SslDomain domain : domainList) {
            domain.setIsYzOver("N");
            domain.setIsAutoSsl("N");
            //保存数据
            domainService.updateSslDomain(domain);
        }
    }

}
